package framework.base;

import framework.runtime.SystemContext;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import tk.mybatis.mapper.common.Mapper;

import java.util.List;
import java.util.function.BiConsumer;

public class SqlExecutor {

    /**
     * 批量处理默认页大小
     */
    public static int BATCH_DEFAULT_SIZE = 1000;


    /**
     * 批量添加数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchAdd(List<T> dataList, Class<M> mapperClass) {
        return batchAdd(BATCH_DEFAULT_SIZE, dataList, mapperClass);
    }

    /**
     * 批量添加数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchAdd(int batchSize, List<T> dataList, Class<M> mapperClass) {
        return batchExecute(batchSize, dataList, mapperClass, (m, t) -> m.insertSelective(t));
    }

    /**
     * 批量执行操作,指定处理函数
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchExecute(int batchSize, List<T> dataList, Class<M> mapperClass, BiConsumer<M, T> function) {
        int totalSize = dataList.size();
        int rows = 0;
        SqlSession session = null;
        SqlSessionFactory factory = SystemContext.getBean(SqlSessionFactory.class);
        try {
            session = factory.openSession(ExecutorType.BATCH);
            M mapper = session.getMapper(mapperClass);
            for (int i = 0; i < totalSize; i += batchSize) {
                int end = Math.min(totalSize, i + batchSize);
                List<T> list = dataList.subList(i, end);
                for (T obj : list) {
                    //mapper.insertSelective(obj);
                    function.accept(mapper, obj);
                }
                session.commit();
                rows += list.size();
            }
        } catch (Exception e) {
            if (session != null) {
                session.rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return rows;
    }

    /**
     * 依据主键批量修改数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchUpdate(List<T> dataList, Class<M> mapperClass) {
        return batchUpdate(BATCH_DEFAULT_SIZE, dataList, mapperClass);
    }

    /**
     * 依据主键批量修改数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchUpdate(int batchSize, List<T> dataList, Class<M> mapperClass) {
        return batchExecute(batchSize, dataList, mapperClass, (m, t) -> m.updateByPrimaryKeySelective(t));
    }


    /**
     * 批量删除数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchDelete(List<T> dataList, Class<M> mapperClass) {
        return batchDelete(BATCH_DEFAULT_SIZE, dataList, mapperClass);
    }

    /**
     * 批量删除数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchDelete(int batchSize, List<T> dataList, Class<M> mapperClass) {
        return batchExecute(batchSize, dataList, mapperClass, (m, t) -> m.delete(t));
    }

    /**
     * 依据主键批量删除数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchDeletePK(List<T> dataList, Class<M> mapperClass) {
        return batchExecute(BATCH_DEFAULT_SIZE, dataList, mapperClass, (m, t) -> m.deleteByPrimaryKey(t));
    }

    /**
     * 依据主键批量删除数据
     *
     * @param dataList
     * @param mapperClass
     * @return
     */
    public static <T, M extends Mapper<T>> int batchDeletePK(int batchSize, List<T> dataList, Class<M> mapperClass) {
        return batchExecute(batchSize, dataList, mapperClass, (m, t) -> m.deleteByPrimaryKey(t));
    }

    /**
     * 添加新数据
     *
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchAdd(List<T> dataList, String sqlId) {
        return batchAdd(BATCH_DEFAULT_SIZE, dataList, sqlId);
    }

    /**
     * 添加新数据
     *
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchAdd(int batchSize, List<T> dataList, String sqlId) {
        int totalSize = dataList.size();
        int rows = 0;
        SqlSession session = null;
        SqlSessionFactory factory = SystemContext.getBean(SqlSessionFactory.class);
        try {
            session = factory.openSession(ExecutorType.BATCH);
            for (int i = 0; i < totalSize; i += batchSize) {
                int end = Math.min(totalSize, i + batchSize);
                List<T> list = dataList.subList(i, end);
                session.insert(sqlId, list);
                session.commit();
                rows += list.size();
            }
        } catch (Exception e) {
            if (session != null) {
                session.rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return rows;
    }

    /**
     * 添加新数据
     *
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchUpdate(List<T> dataList, String sqlId) {
        return batchUpdate(BATCH_DEFAULT_SIZE, dataList, sqlId);
    }

    /**
     * 添加新数据
     *
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchUpdate(int batchSize, List<T> dataList, String sqlId) {
        int totalSize = dataList.size();
        int rows = 0;
        SqlSession session = null;
        SqlSessionFactory factory = SystemContext.getBean(SqlSessionFactory.class);
        try {
            session = factory.openSession(ExecutorType.BATCH);
            for (int i = 0; i < totalSize; i += batchSize) {
                int end = Math.min(totalSize, i + batchSize);
                List<T> list = dataList.subList(i, end);
                session.update(sqlId, list);
                session.commit();
                rows += list.size();
            }
        } catch (Exception e) {
            if (session != null) {
                session.rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return rows;
    }

    /**
     * 添加新数据
     *
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchDelete(List<T> dataList, String sqlId) {
        return batchDelete(BATCH_DEFAULT_SIZE, dataList, sqlId);
    }

    /**
     * 添加新数据
     *
     * @param batchSize
     * @param dataList
     * @param sqlId
     * @return
     */
    public static <T> int batchDelete(int batchSize, List<T> dataList, String sqlId) {
        int totalSize = dataList.size();
        int rows = 0;
        SqlSession session = null;
        SqlSessionFactory factory = SystemContext.getBean(SqlSessionFactory.class);
        try {
            session = factory.openSession(ExecutorType.BATCH);
            for (int i = 0; i < totalSize; i += batchSize) {
                int end = Math.min(totalSize, i + batchSize);
                List<T> list = dataList.subList(i, end);
                session.delete(sqlId, list);
                session.commit();
                rows += list.size();
            }
        } catch (Exception e) {
            if (session != null) {
                session.rollback();
            }
            throw e;
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return rows;
    }


}
